﻿using LightCAD.Core.Elements;
using LightCAD.Core;
using LightCAD.Runtime;
using SkiaSharp;
using System;
using System.Collections.Generic;
using LightCAD.MathLib;
using netDxf.Blocks;

namespace LightCAD.Drawing.Actions
{
    public class DrawingFrameAction : ElementAction
    {
        private DrawingFrameAction() { }
        public DrawingFrameAction(IDocumentEditor docEditor)
         : base(docEditor)
        {
            this.commandCtrl.WriteInfo("命令：DrawingFrame");
            this.LcDocument = docRt.Document;
            this.LcDocument.PropertyChangedAfter += LcDocument_PropertyChangedAfter;
            this.LcDocument.ObjectChangedAfter += LcDocument_ObjectChangedAfter;
        }

        private void LcDocument_ObjectChangedAfter(object? sender, ObjectChangedEventArgs e)
        {
            if (e.Type == ObjectChangeType.Insert)
            {
                var lcElement = (LcElement)e.Target;
                //AddElement(lcElement);
            }
            else if (e.Type == ObjectChangeType.Remove)
            {
                var lcElement = (LcElement)e.Target;
                DelElement(lcElement);
            }
        }

        private void LcDocument_PropertyChangedAfter(object? sender, PropertyChangedEventArgs e)
        {
            var lcElement = (LcElement)e.Object;
            //AddElement(lcElement);
        }
        public void AddElement(LcElement lcElement)
        {
            if (lcElement is LcDrawing)
            {
                return;
            }
            foreach (var building in this.LcDocument.Buildings)
            {
                foreach (var lcLevel in building.Levels)
                {
                    foreach (var lcDrawing in lcLevel.Drawings)
                    {
                        if (lcDrawing.Elements.ContainsKey(lcElement.Id))
                        {
                            lcDrawing.Elements.Remove(lcElement.Id);
                            break;
                        }
                    }
                    foreach (var lcDrawing in lcLevel.Drawings)
                    {
                        var box = lcDrawing.BoundingBox;
                        if (lcElement.BoundingBox.IntersectsBox(box))
                        {
                            if (lcElement is LcBasePoint)
                            {
                                lcDrawing.buildingBasePoint = lcElement as LcBasePoint;
                            }
                            else
                            {
                                if (!lcDrawing.Elements.ContainsKey(lcElement.Id))
                                {
                                    lcDrawing.Elements.Add(lcElement.Id, lcElement);
                                }
                            }
                            return;
                        }
                    }
                }
            }
        }
        public void DelElement(LcElement lcElement)
        {
            foreach (var building in this.LcDocument.Buildings)
            {
                foreach (var lcLevel in building.Levels)
                {
                    if (lcElement is LcDrawing)
                    {
                        if (lcLevel.Drawings.Contains(lcElement as LcDrawing))
                        {
                            lcLevel.Drawings.Remove(lcElement as LcDrawing);
                        }
                    }
                    else
                    {
                        foreach (var lcDrawing in lcLevel.Drawings)
                        {
                            if (lcDrawing.Elements.ContainsKey(lcElement.Id))
                            {
                                lcDrawing.Elements.Remove(lcElement.Id);
                                break;
                            }
                        }

                        foreach (var lcDrawing in lcLevel.Drawings)
                        {
                            var box = lcDrawing.BoundingBox;
                            if (lcElement.BoundingBox.IntersectsBox(box))
                            {
                                if (lcElement is LcBasePoint)
                                {
                                    if (lcDrawing.buildingBasePoint == lcElement as LcBasePoint)
                                    {
                                        lcDrawing.buildingBasePoint = null;
                                    }
                                }
                                return;

                            }
                        }
                    }
                }
            }
        }
        private static readonly LcCreateMethod[] CreateMethods;
        public LcDocument LcDocument { get; set; }

        static DrawingFrameAction()
        {
            CreateMethods = new LcCreateMethod[1];
            CreateMethods[0] = new LcCreateMethod()
            {
                Name = "DrawingFrame",
                Description = "创建图框",
                Steps = new LcCreateStep[]
                                                   {
                                                       new LcCreateStep { Name = "Step0", Options = "指定定位点:" },
                                                       new LcCreateStep { Name = "Step1", Options = "指定定位点或[放弃(U)]:" },
                                                   }
            };
        }
        internal static void Initilize()
        {
            ElementActions.BlockRef = new DrawingFrameAction();
            LcDocument.ElementActions.Add(BuiltinElementType.Drawing, ElementActions.BlockRef);
        }

        private Vector2 point { get; set; }

        private PointInputer inputer { get; set; }
        private string DrawingName;
        private List<LcLevel> lcLevels = new List<LcLevel>();
        private LcBuilding lcBuilding;
        private Vector2 basePoint;
        private Vector2 firstPoint;
        private List<LcElement> selectedElements = new List<LcElement>();

        public async void ExecCreate(string[] args = null)
        {
            this.StartCreating();
            this.inputer = new PointInputer(this.docEditor);
            var curMethod = CreateMethods[0];
            var elementSetInputer = new ElementSetInputer(this.docEditor);

            var win = (IFrameDefWindow)AppRuntime.UISystem.CreateWindow("DrawingFrameWindow", this);
            if (this.docRt.Action.SelectedElements.Count > 0)
            {

                win.Elements = new List<LcElement>();
            }
        ShowDlg:
            var result = AppRuntime.UISystem.ShowDialog(win);
            if (result == LcDialogResult.OK)
            {
                //DocumentManager.CurrentRecorder.BeginAction("DrawingFrame");
                if (win.CurrentAction == "SelectPoint")
                {
                    var result1 = await this.inputer.Execute("选择第一个点：");
                    if (result1 == null)
                    {
                        goto End;
                    }
                    if (result1.ValueX != null)
                    {
                        firstPoint = (Vector2)result1.ValueX;
                        var result2 = await this.inputer.Execute("选择第二个点：");
                        if (result2 == null)
                        {
                            goto End;
                        }
                        if (result2.ValueX != null)
                        {
                            Box2 box2D = new Box2().SetFromPoints((Vector2)result1.ValueX, (Vector2)result2.ValueX);
                            win.Box = box2D;
                            basePoint = box2D.LeftBottom.Clone();
                        }
                    }
                    goto ShowDlg;
                }
                else if (win.CurrentAction == "OK")//
                {
                    this.DrawingName = win.FrameName;
                    this.lcBuilding = win.LcBuilding;
                    this.lcLevels = win.LcLevels;
                    this.CreateOutLine(win);
                    this.CreateDrawing();
                    this.docRt.Action.CancelAll();
                    goto End;
                }
                else if (win.CurrentAction == "Cancel")
                {
                    goto End;
                }
            }
        End:
            this.inputer = null;
            this.EndCreating();

            //DocumentManager.CurrentRecorder.EndAction();
        }
        public void CreateOutLine(IFrameDefWindow win)
        {
            Box2 box2D = (Box2)win.Box;

            //selectedElements.Add(this.docRt.Document.ModelSpace.AddLine(box2D.LeftTop, box2D.RightTop));
            //selectedElements.Add(this.docRt.Document.ModelSpace.AddLine(box2D.RightTop, box2D.RightBottom));
            //selectedElements.Add(this.docRt.Document.ModelSpace.AddLine(box2D.RightBottom, box2D.LeftBottom));
            //selectedElements.Add(this.docRt.Document.ModelSpace.AddLine(box2D.LeftBottom, box2D.LeftTop));

            List<Vector2> points = new List<Vector2>();
            points.Add(box2D.LeftTop.Clone());
            points.Add(box2D.RightTop.Clone());
            points.Add(box2D.RightBottom.Clone());
            points.Add(box2D.LeftBottom.Clone());
            for (int i = 0; i < points.Count; i++)
            {
                Vector2 startPoint = points[i];
                Vector2 entPoint;
                if (i == points.Count - 1)
                {
                    entPoint = points[0];
                }
                else
                {
                    entPoint = points[i + 1];
                }
                var line = this.docRt.Document.CreateObject<LcLine>();
                line.Start = startPoint.Clone();
                line.End = entPoint.Clone();
                selectedElements.Add(line);
            }
            //增加内框名
            var nameFrameLeftTop = box2D.LeftTop + new Vector2(0, 600);
            var nameFrameLeftBottom = box2D.LeftTop;

            var nameFrameRightTop = nameFrameLeftTop + new Vector2(Math.Abs(box2D.RightTop.X - box2D.LeftTop.X) / 2, 0);
            var nameFrameRightBottom = nameFrameLeftBottom + new Vector2(Math.Abs(box2D.RightTop.X - box2D.LeftTop.X) / 2, 0);
           points=new List<Vector2>();
            points.Add(nameFrameLeftTop.Clone());
            points.Add(nameFrameRightTop.Clone());
            points.Add(nameFrameRightBottom.Clone());
            points.Add(nameFrameLeftBottom.Clone());
            for (int i = 0; i < points.Count; i++)
            {
                Vector2 startPoint= points[i];
                Vector2 entPoint;
                if (i==points.Count-1)
                {
                    entPoint = points[0];
                }
                else
                {
                    entPoint = points[i + 1];
                }
                var line = this.docRt.Document.CreateObject<LcLine>();
                line.Start = startPoint.Clone();
                line.End = entPoint.Clone();
                selectedElements.Add(line);
            }
       
      
            LcText lcText = docRt.Document.CreateObject<LcText>();
            lcText.Start = nameFrameLeftBottom + new Vector2(0, 150);
            lcText.TextStart = nameFrameLeftBottom + new Vector2(0, 150);
            lcText.Boxstart = nameFrameLeftBottom + new Vector2(0, 150);
            lcText.Text = win.FrameName;
            lcText.Heigh = 300;
            //字体
            lcText.Typeface = "黑体";
            //默认值
            lcText.Tilt = 0;
            lcText.Widthfactor = 1;
            //计算文字角度
            lcText.Rotate = 0;
            lcText.Alignment = "左对齐";
            selectedElements.Add(lcText);
        }
        public void CreateDrawing()
        {
            var doc = this.docRt.Document;
            var block = doc.CreateObject<LcDrawingFrame>();
            block.Name = this.DrawingName;

            foreach (var element in selectedElements)
            {
                //doc.ModelSpace.RemoveElement(element);
                block.InsertElement(element);
            }

            //使用基点，将元素的世界坐标转换为局部坐标
            foreach (var element in selectedElements)
            {
                element.Translate(-basePoint.Clone());
            }

            //转换完成后，将基点的局部坐标设置为零零
            block.BasePoint = Vector2.Zero;
            doc.Blocks.Add(block);//TODO 需要触发事件

            var blockRef = doc.CreateObject<LcDrawing>(block);
            blockRef.Name = this.DrawingName;
            blockRef.Set(matrix: Matrix3.GetTranslate(basePoint));
            foreach (var lcLevel in this.lcLevels)
            {
                lcLevel.Drawings.Add(blockRef);
            }
            doc.ModelSpace.InsertElement(blockRef);
        }

        public override void Draw(SKCanvas canvas, LcElement element, Vector2 offSet)
        {
            Draw(canvas, element, Matrix3.GetTranslate(offSet));
        }
        public override void Draw(SKCanvas canvas, LcElement element, Matrix3 matrix)
        {
            var lcDrawing = element as LcDrawing;
            RefStack.Push(lcDrawing);
            try
            {
                var mat = matrix * lcDrawing.Matrix;
                //List<Text> texts = new List<Text>();
                foreach (var ele in lcDrawing.Block.Elements)
                {
                    //if (ele is Text)
                    //{
                    //    texts.Add((Text)ele);
                    //    continue;
                    //}

                    var eleAction = (ele.RtAction as ElementAction);

                    eleAction.SetViewport(this.vportRt).Draw(canvas, ele, mat);

                }
                var elements = this.docRt.Document.ModelSpace.Elements;
                List<long> noELe = new List<long>();
                foreach (var id in lcDrawing.Elements.Keys)
                {
                    if (!elements.Contains(id))
                    {
                        noELe.Add(id);
                    }
                }
                foreach (var delID in noELe)
                {
                    lcDrawing.Elements.Remove(delID);
                }
                foreach (var lcElement in elements)
                {
                    var box = lcDrawing.BoundingBox;
                    if (lcElement.BoundingBox.IntersectsBox(box))
                    {
                        if ((lcElement is LcDrawing) || (lcElement is LcAxisLine) || (lcElement is LcAxisGrid))
                        {
                            continue;
                        }
                        if (lcElement is LcBasePoint)
                        {
                            lcDrawing.buildingBasePoint = lcElement as LcBasePoint;
                        }
                        else
                        {
                            if (!lcDrawing.Elements.ContainsKey(lcElement.Id))
                            {
                                lcDrawing.Elements.Add(lcElement.Id, lcElement);
                            }
                        }
                    }
                }

            }
            catch (Exception ex)
            {
            }
            finally
            {
                RefStack.Pop();
            }

            if (matrix == Matrix3.Identity)
            {
                //var leftTop = this.vportRt.ConvertWcsToScr(lcDrawing.BoundingBox.LeftTop);
                //var rightBottom = this.vportRt.ConvertWcsToScr(lcDrawing.BoundingBox.RightBottom);
                //canvas.DrawRect((float)leftTop.X, (float)leftTop.Y, (float)rightBottom.X - (float)leftTop.X, (float)rightBottom.Y - (float)leftTop.Y, Constants.SilverPen);
            }
        }

        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var lcDrawing = element as LcDrawing; //getHel
            var grips = new List<ControlGrip>();

            var insertPoint = new ControlGrip
            {
                Element = lcDrawing,
                Name = "InsertPoint",
                Position = lcDrawing.Matrix.GetTranslateVector()
            };
            grips.Add(insertPoint);
            return grips.ToArray();
        }
        private string _gripName;

        private Vector2 _position;
        private LcDrawing _lcDrawing;

        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {
            var lcDrawing = element as LcDrawing;

            _lcDrawing = lcDrawing;
            if (!isEnd)
            {
                _gripName = gripName;
                _position = position;
            }
            else
            {
                if (gripName == "InsertPoint")
                    lcDrawing.Set(matrix: Matrix3.GetTranslate(position));
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="canvas"></param>
        public override void DrawDragGrip(SKCanvas canvas)
        {
            if (_lcDrawing == null) return;
            var box = _lcDrawing.BoundingBox;
            Vector2 anglePoint1 = box.LeftTop;
            Vector2 anglePoint2 = box.RightTop;
            Vector2 anglePoint3 = box.RightBottom;
            Vector2 anglePoint4 = box.LeftBottom;

            var SKPoint1 = this.vportRt.ConvertWcsToScr(anglePoint1).ToSKPoint();
            var SKPoint2 = this.vportRt.ConvertWcsToScr(anglePoint2).ToSKPoint();
            var SKPoint3 = this.vportRt.ConvertWcsToScr(anglePoint3).ToSKPoint();
            var SKPoint4 = this.vportRt.ConvertWcsToScr(anglePoint4).ToSKPoint();
            //辅助元素的颜色 
            canvas.DrawLine(SKPoint1, SKPoint2, Constants.draggingPen);
            canvas.DrawLine(SKPoint2, SKPoint3, Constants.draggingPen);
            canvas.DrawLine(SKPoint3, SKPoint4, Constants.draggingPen);
            canvas.DrawLine(SKPoint4, SKPoint1, Constants.draggingPen);
        }
        public override void DrawAuxLines(SKCanvas canvas)
        {
            if (firstPoint == null) return;
            var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            var wcs_mp = this.vportRt.ConvertScrToWcs(mp);

            Vector2 anglePoint1 = (Vector2)firstPoint;
            Vector2 anglePoint3 = wcs_mp;
            Vector2 anglePoint2 = new Vector2(anglePoint1.X, anglePoint3.Y);
            Vector2 anglePoint4 = new Vector2(anglePoint3.X, anglePoint1.Y);

            var SKPoint1 = this.vportRt.ConvertWcsToScr(anglePoint1).ToSKPoint();
            var SKPoint2 = this.vportRt.ConvertWcsToScr(anglePoint2).ToSKPoint();
            var SKPoint3 = this.vportRt.ConvertWcsToScr(anglePoint3).ToSKPoint();
            var SKPoint4 = this.vportRt.ConvertWcsToScr(anglePoint4).ToSKPoint();
            //辅助元素的颜色 
            canvas.DrawLine(SKPoint1, SKPoint2, new SKPaint { Color = this.vportRt.GetAuxColorValue(), IsStroke = true });
            canvas.DrawLine(SKPoint2, SKPoint3, new SKPaint { Color = this.vportRt.GetAuxColorValue(), IsStroke = true });
            canvas.DrawLine(SKPoint3, SKPoint4, new SKPaint { Color = this.vportRt.GetAuxColorValue(), IsStroke = true });
            canvas.DrawLine(SKPoint4, SKPoint1, new SKPaint { Color = this.vportRt.GetAuxColorValue(), IsStroke = true });
        }


    }
}
